package com.ease.map {
    import com.gskinner.motion.GTween;
    import com.gskinner.motion.easing.Cubic;
    import com.ease.map.MapSupport;
    import com.ease.map.RemoteCaller;
    import com.ease.map.common.enum.HandlerEnum;
    import com.ease.map.common.enum.MapActionEnum;
    import com.ease.map.constant.LayerIdConstants;
    import com.ease.map.control.Control;
    import com.ease.map.control.IControl;
    import com.ease.map.control.ILegendDisplayControlAware;
    import com.ease.map.cursor.CrossCursor;
    import com.ease.map.cursor.HandCursor;
    import com.ease.map.events.LayerEvent;
    import com.ease.map.events.MapEvent;
    import com.ease.map.feature.Feature;
    import com.ease.map.geometry.basetype.Extent;
    import com.ease.map.geometry.basetype.Location;
    import com.ease.map.geometry.basetype.Pixel;
    import com.ease.map.geometry.basetype.Size;
    import com.ease.map.geometry.basetype.Unit;
    import com.ease.map.handler.IHandler;
    import com.ease.map.handler.feature.SelectFeaturesHandler;
    import com.ease.map.layer.FeatureLayer;
    import com.ease.map.layer.GraphicLayer;
    import com.ease.map.layer.Layer;
    import com.kgis.map.projection.Projection;
    import com.kgis.widgets.managers.ErrorManager;
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.DisplayObject;
    import flash.display.Sprite;
    import flash.geom.Rectangle;
    import flash.net.*;
    import flash.utils.Dictionary;
    import flash.utils.getQualifiedClassName;
    
    import mx.collections.ArrayCollection;
    import mx.managers.CursorManager;

    /**
     * Map地图类
     * 地图控件上可添加背景瓦片图层、矢量设施图层、以及其他界面控件、操作handler
     * 该类是个纯as3控件，
     * 后续会封装出一个UIComponent的Map控件 供应用在mxml里直接使用，如： <MapCtrl></MapCtrl>
     */
    public class Map extends Sprite {
        /**瓦片读取失败后重新发请求次数*/
        public static const IMAGE_RELOAD_ATTEMPTS:Number = 0;
        /**缺省地图分辨率，maxextent下的地图分辨率  地图分辨率
         * 地图分辨率指：屏幕上1个像素对应的地图单位
         */
        public static const DEFAULT_NOMINAL_RESOLUTION:Number = 1.40625;
        /**地图分辨率容差*/
        public static const RESOLUTION_TOLERANCE:Number = 0.000001;
        /**地图最大放大等级*/
        public static const DEFAULT_NUM_ZOOM_LEVELS:uint = 18;
        /**缺省地图坐标系编码*/
        public static const DEFAULT_SRS_CODE:String = "EPSG:4326";
        /**地图投影*/
        private var _projection:Projection = null;

        /**地图窗口大小（宽、高）*/
        private var _size:Size = null;
        /**地图当前的zoom等级*/
        private var _zoom:Number = NaN;

        /**map-->layercontainer-->layer*/
        private var _layerContainer:Sprite = null;
        /**The location where the layer container was re-initialized (on-zoom)*/
        private var _layerContainerOrigin:Location = null;

        /**地图控件*/
        private var _controls:Vector.<IControl> = new Vector.<IControl>();
        /**地图操作handler*/
        private var _handlers:Vector.<IHandler> = new Vector.<IHandler>();
        /**是否正在缩放*/
        private var _zooming:Boolean = false;
        /**是否正在加载数据*/
        private var _loading:Boolean;
        /**地图中心点地理坐标*/
        private var _center:Location = null;
        /**地图最大范围*/
        private var _maxExtent:Extent = null;
        /**地图最大范围时的每个像素的分辨率，即每个像素代表的地理单位*/
        private var _maxResolution:Number = DEFAULT_NOMINAL_RESOLUTION;
        /**地图最大放大等级*/
        private var _numZoomLevels:Number = DEFAULT_NUM_ZOOM_LEVELS;
        /**地图分辨率数组，记录从最小--最大等级对应的地图分辨率*/
        private var _resolutions:Array = null;

        private var _destroying:Boolean = false;
        private var _tweenZoomEnabled:Boolean = false;
        private var _proxy:String = null;

        /**zoom以及漫游时的效果使用*/
        private var _bitmapTransition:Sprite;
        /**矢量符号库*/
        private var _symbolDic:Dictionary = null;
        private var _remoteCaller:RemoteCaller = null;
        /**地图辅助类*/
        private var _mapSupport:MapSupport = null;
        /**地图操作模式*/
        private var _operateMode:int;
        /**鼠标光标*/
        protected var _handCursor:HandCursor;
        /**图层控制*/
        private var _legendControl:ILegendDisplayControlAware;

        public var serverUrl:String;

        /**逻辑图id*/
        private var _logicalMapId:Number = 0;
		
		/**高亮的设施列表*/
		private var _highLightFeatures:Vector.<Feature>=new Vector.<Feature>();

        /**
         * Map constructor
         *
         * @param width 地图窗口宽
         * @param height 地图窗口高
         */
        public function Map(width:Number = 600, height:Number = 400) {
            super();

            this._projection = new Projection(Map.DEFAULT_SRS_CODE);
            this.size = new Size(width, height);
            this._layerContainer = new Sprite();

            this._layerContainer.graphics.clear();
            this._layerContainer.graphics.beginFill(0xFFFFFF, 0);
            this._layerContainer.graphics.drawRect(0, 0, this.size.w, this.size.h);
            this._layerContainer.graphics.endFill();
            this._layerContainer.width = this.size.w;
            this._layerContainer.height = this.size.h;
            this.addChild(this._layerContainer);

            var graphicLayer:GraphicLayer = new GraphicLayer(LayerIdConstants.ANCHORLAYER_LAYERID, "$graphiclayer$");
            this.addLayer(graphicLayer, false);

            this.generateResolutions();

            this.addEventListener(LayerEvent.LAYER_LOAD_START, layerLoadHandler);
            this.addEventListener(LayerEvent.LAYER_LOAD_END, layerLoadHandler);

            this._mapSupport = new MapSupport(this);
            this.operateMode = MapActionEnum.MAP_PAN;

//            legendControl.visible = false;
//            legendControl.resizeable = true;
        }

        /**地图操作模式*/
        public function get operateMode():int {
            return _operateMode;
        }

        /**
         * @private
         */
        public function set operateMode(value:int):void {
            var selectfeatureshandler:SelectFeaturesHandler;
            switch (value) {
                case MapActionEnum.MAP_PAN:
                    this.getHandler(HandlerEnum.FEATURE_CLICK_HANDLER).active = true;
                    selectfeatureshandler = this.getHandler(HandlerEnum.SELECT_FEATURES_HANDLER) as SelectFeaturesHandler;
                    selectfeatureshandler.active = true;
                    selectfeatureshandler.enableBoxSelection = false;
                    selectfeatureshandler.enableClickSelection = true;
                    this.getHandler(HandlerEnum.DRAG_HANDLER).active = true;
                    this.getHandler(HandlerEnum.WHEEL_HANDLER).active = true;
                    CursorManager.removeAllCursors();
                    break;
                case MapActionEnum.MAP_DRAW:
                    this.getHandler(HandlerEnum.FEATURE_CLICK_HANDLER).active = false;
                    this.getHandler(HandlerEnum.SELECT_FEATURES_HANDLER).active = false;
                    this.getHandler(HandlerEnum.DRAG_HANDLER).active = true;
                    this.getHandler(HandlerEnum.WHEEL_HANDLER).active = true;
                    CursorManager.setCursor(CrossCursor);
                    break;

                case MapActionEnum.MAP_SELECT:
                    this.getHandler(HandlerEnum.FEATURE_CLICK_HANDLER).active = true;
                    selectfeatureshandler = this.getHandler(HandlerEnum.SELECT_FEATURES_HANDLER) as SelectFeaturesHandler;
                    selectfeatureshandler.active = true;
                    selectfeatureshandler.enableBoxSelection = true;
                    selectfeatureshandler.enableClickSelection = true;
                    this.getHandler(HandlerEnum.DRAG_HANDLER).active = false;
                    this.getHandler(HandlerEnum.WHEEL_HANDLER).active = true;
                    CursorManager.removeAllCursors();
                    break;
                case MapActionEnum.MAP_EDIT:
                    this.getHandler(HandlerEnum.FEATURE_CLICK_HANDLER).active = false;
                    this.getHandler(HandlerEnum.SELECT_FEATURES_HANDLER).active = false;
                    this.getHandler(HandlerEnum.DRAG_HANDLER).active = true;
                    this.getHandler(HandlerEnum.WHEEL_HANDLER).active = true;
                    CursorManager.removeAllCursors();
                    break;

            }
            _operateMode = value;
        }

        /**
         * 缺省地图最大范围
         */
        public static function get DEFAULT_MAXEXTENT():Extent {
            return new Extent(-180, -90, 180, 90);
        }

        /**
         * 缺省地图投影
         */
        public static function get DEFAULT_PROJECTION():Projection {
            return Projection.getProjProjection(DEFAULT_SRS_CODE);
        }

//		//设置鼠标光标
//		private function ShowHandCursor():void
//		{
//			if(this.operateMode==MapActionEnum.MAP_PAN)
//			{
//				if (_handCursor== null)
//				{
//					//替换为手形
//					_handCursor = new HandCursor(this)
//					this.rawChildren.addChild(_handCursor);
//				}
//			}
//		}

        /**
         * 生成resolutions数组.
         * 按照以下原则生成 : resolutions[i] = resolutions[i-1] / 2
         */
        public function generateResolutions(zoomLevels:uint = Map.DEFAULT_NUM_ZOOM_LEVELS, nominalResolution:Number = Map.DEFAULT_NOMINAL_RESOLUTION):void {
            // 放大等级必须大于0
            if (zoomLevels == 0) {
                zoomLevels = 1;
            }

            if (!_resolutions) {
                this._resolutions = new Array();
            }
            else {
                this._resolutions.splice(0);
            }

            this._resolutions.push(nominalResolution);
            var i:int = 1;
            for (i; i < zoomLevels; i++) {
                this._resolutions.push(this.resolutions[i - 1] / 2);
            }
            this._resolutions.sort(Array.NUMERIC | Array.DESCENDING);
        }

        /**
         * 获取extent对应的zoom等级
         */
        public function getZoomForExtent(extent:Extent):Number {
            var viewSize:Size = this.size;
            var idealResolution:Number = Math.max(extent.width / viewSize.w, extent.height / viewSize.h);
            return this.getZoomForResolution(idealResolution);
        }

        /**
         * 根据分辨率获取对应的zoomlevel
         */
        public function getZoomForResolution(resolution:Number):Number {
            if (resolution > this.resolutions[0]) {
                return 0;
            }
            if (resolution < this.resolutions[this.resolutions.length - 1]) {
                return this.resolutions.length - 1;
            }
            var i:int = 1;
            var j:int = this.resolutions.length - 1;
            for (i; i < j; i++) {
                if ((this.resolutions[i] < resolution) && (Math.abs(this.resolutions[i] - resolution) > RESOLUTION_TOLERANCE)) {
                    break;
                }
            }
            return i - 1;
        }

        /**
         * 最大分辨率
         */
        public function get maxResolution():Number {
            var maxRes:Number = this._maxResolution;

            if (isNaN(maxRes) && this.resolutions && (this.resolutions.length > 0)) {
                maxRes = this.resolutions[0];
            }
            return maxRes;
        }

        public function set maxResolution(value:Number):void {
            this._maxResolution = value;
            this.generateResolutions(this.numZoomLevels, value);
        }

        /**
         * Number of zoom levels (resolutions array length)
         */
        public function get numZoomLevels():Number {
            return this.resolutions.length;
        }

        public function set numZoomLevels(value:Number):void {
            this._numZoomLevels = value;
            this.generateResolutions(value, this.maxResolution);
        }

        /**
         * 地图分辨率数组，记录各个level（0-n）的对应的分辨率
         */
        public function get resolutions():Array {
            return this._resolutions;
        }

        public function set resolutions(value:Array):void {
            this._resolutions = value;
            if (this._resolutions == null || this._resolutions.length == 0) {
                this.generateResolutions();
            }
            this._resolutions.sort(Array.NUMERIC | Array.DESCENDING);
        }

        /**
         * 重置地图，清除所有图层、操作handler、以及controls
         */
        public function reset():void {
            this.removeAllLayers();

            if (this._handlers != null) {
                for each (var handler:IHandler in this._handlers) {
                    this.removeHandler(handler);
                }
            }

            if (this._controls != null) {
                for each (var control:IControl in this._controls) {
                    this.removeControl(control);
                }
            }
        }

        /**
         * 添加图层到地图
         * 同时触发LayerEvent.LAYER_ADDED事件.
         *
         * @param 要添加的图层.
         * @return 图层添加成功true , 添加失败false.
         */
        public function addLayer(layer:Layer, redraw:Boolean = false):Boolean {
            var i:uint = 0;
            var j:uint = this.layers.length;
            for (; i < j; i++) {
                if (this.layers[i].id == layer.id) {
                    trace("该layerid的图层已经存在");
                    return false;
                }
            }

            this._layerContainer.addChild(layer);

            layer.map = this;

            if (redraw) {
                layer.redraw();
            }

            this.dispatchEvent(new LayerEvent(LayerEvent.LAYER_ADDED, layer));

            return true;
        }

        /**
         * 添加一组图层.
         * @param 图层数组.
         */
        public function addLayers(layers:Vector.<Layer>):void {
            var j:uint = layers.length;
            var i:uint = 0;
            for (i; i < j; ++i) {
                this.addLayer(layers[i]);
            }
        }

        /**
         * 根据图层名称获取图层对象.
         * @param 图层名称.
         * @return 图层名称对应的图层,如果找不到相应的图层，这返回Null.
         *
         */
        public function getLayerByName(name:String):Layer {
            var foundLayer:Layer = null;
            var i:uint = 0;
            var j:uint = this.layers.length;
            for (; i < j; ++i) {
                var layer:Layer = this.layers[i];
                if (layer.name == name) {
                    foundLayer = layer;
                    break;
                }
            }
            return foundLayer;
        }

        /**
         * 根据图层id获取图层对象.
         * @param 图层名称.
         * @return 图层名称对应的图层,如果找不到相应的图层，这返回Null.
         *
         */
        public function getLayerById(id:int):Layer {
            var foundLayer:Layer = null;
            var i:uint = 0;
            var j:uint = this.layers.length;
            for (; i < j; ++i) {
                var layer:Layer = this.layers[i];
                if (layer.id == id) {
                    foundLayer = layer;
                    break;
                }
            }
            return foundLayer;
        }

        /**
         * 移除一个图层
         * layer.destroy？？
         *
         * 触发LayerEvent.LAYER_REMOVED事件.
         *
         * @param 需要移除的图层.
         */
        public function removeLayer(layer:Layer):void {
            this._layerContainer.removeChild(layer);
            layer.destroy();
            var l:Vector.<Layer> = this.layers;
            var i:int = l.indexOf(layer);
            if (i > -1)
                l.splice(i, 1);

            this.dispatchEvent(new LayerEvent(LayerEvent.LAYER_REMOVED, layer));
            layer = null;
        }


        /**
         * 移除地图上所有图层
         */
        public function removeAllLayers():void {
            for (var i:int = this.layers.length - 1; i >= 0; i--) {
                removeLayer(this.layers[i]);
            }
        }

        /**
         * 移除地图上所有高亮图层(layerid<0)
         */
        public function removeAllHiLightLayers():void {
            for (var i:int = this.layers.length - 1; i >= 0; i--) {
                if (this.layers[i].id < 0) {
                    removeLayer(this.layers[i]);
                }
            }
        }

        /**
         * 添加一个控件到地图.
         *
         * @param 需要添加的控件.
         * @param attach 控件是否作为地图的儿子
         */
        public function addControl(control:IControl, attach:Boolean = true):void {
            if (!control) {
                return;
            }
            var i:uint = 0;
            var j:uint = this._controls.length;
            for (; i < j; ++i) {
                if (control == this._controls[i]) {
                    return;
                }
            }
            // 新控件
            if (i == j) {
                this._controls.push(control);
                control.map = this;
                control.draw();
                if (attach) {
                    this.addChild(control as Sprite);
                }
            }
        }

        /**
         * 移除一个控件
         */
        public function removeControl(control:IControl):void {
            var newControls:Vector.<IControl> = new Vector.<IControl>();
            for each (var mapControl:IControl in this._controls) {
                if (mapControl == control) {
                    control.active = false;
                    this.removeChild(control as Sprite);
                    control = null;
                }
                else {
                    newControls.push(mapControl);
                }
            }
            this._controls = newControls;
        }

        /**
         * 添加一个地图操作handler
         */
        public function addHandler(handler:IHandler):void {
            if (!handler) {
                ErrorManager.showErrorMessage("Map.addHandler: handler为null");
                return;
            }

            if (!handler.map) {
                handler.map = this;
            }
            else if (handler.map != this) {
                ErrorManager.showErrorMessage("Map.addHandler: handler不是与本地图关联");
                return;
            }

            var i:uint = 0;
            var j:uint = this.handlers.length;
            for (; i < j; ++i) {
                if (handler == this.handlers[i]) {
                    trace("Map.addHandler: handler对象已经存在(" + getQualifiedClassName(handler) + ")");
                    return;
                }
                if (getQualifiedClassName(handler) == getQualifiedClassName(this.handlers[i])) {
                    trace("Map.addHandler: 另一个同名的handler类已经存在 " + getQualifiedClassName(handler));
                    return;
                }
            }
            // 新handler
            if (i == j) {
                trace("Map.addHandler: 新增一个handler " + getQualifiedClassName(handler));
                this._handlers.push(handler);
            }
        }

        /**
         * 移除一个handler
         */
        public function removeHandler(handler:IHandler):void {
            var newHandlers:Vector.<IHandler> = new Vector.<IHandler>();
            for each (var mapHandler:IHandler in this._handlers) {
                if (mapHandler == handler) {
                    handler.active = false;
                    handler = null;
                }
                else {
                    newHandlers.push(mapHandler);
                }
            }
            this._handlers = newHandlers;
        }

        /**
         * 根据名称获取一个handler
         */
        public function getHandler(value:String):IHandler {
            var handler:IHandler = null;
            for each (var mapHandler:IHandler in this._handlers) {
                if (mapHandler.name == value) {
                    handler = mapHandler;
                }
            }
            return handler;
        }

        public function getControlByName(name:String):Control {
            for each (var control:Control in controls) {
                if (control.name == name) {
                    return control;
                }
            }
            return null;;
        }

        /**
         * 移动地图
         *
         * @param dx 水平像素偏移量
         * @param dy 垂直像素偏移量
         * @param tween 是否使用 tween效果
         */
        public function pan(dx:int, dy:int, tween:Boolean = false):void {
            if ((dx == 0) && (dy == 0)) {
                return;
            }
            if (this.center) {
                var newCenterPx:Pixel = this.getMapPxFromLocation(this.center).add(dx, dy);
                var newCenterLocation:Location = this.getLocationFromMapPx(newCenterPx);
                this.moveTo(newCenterLocation, NaN, tween);
            }
        }

        /**
         * 移动或放大缩小地图
         *
         * This method shoud be refactored in order to make panning and zooming more independant.
         *
         * @param lonlat the new center location.
         * @param zoom optional zoom level
         * @param dragging Specifies whether or not to trigger movestart/end events
         * @param forceZoomChange Specifies whether or not to trigger zoom change events (needed on baseLayer change)
         * @param dragTween Tween effect when panning
         * @param zoomTween Tween effect when zooming
         *
         */
        public function moveTo(newCenter:Location, newZoom:Number = NaN, dragTween:Boolean = false, zoomTween:Boolean = false):void {
            var zoomChanged:Boolean = (this.isValidZoomLevel(newZoom) && (newZoom != this._zoom));
            var validLocation:Boolean = this.isValidLocation(newCenter);
            var mapEvent:MapEvent = null;

            if (newCenter && !validLocation) {
                trace("Not a valid center, so do nothing");
                return;
            }

            // If the map is not initialized, the center of the extent is used
            // as the current center
            if (!this.center && !validLocation) {
                newCenter = this.maxExtent.center;
            }
            else if (this.center && !newCenter) {
                newCenter = this.center;
            }

            var centerChanged:Boolean = validLocation && (!newCenter.equals(this.center));
            validLocation = this.isValidLocation(newCenter);
            var oldZoom:Number = this._zoom;
            if (!zoomChanged) {
                newZoom = oldZoom;
            }
            var oldCenter:Location = this._center;

            if (zoomChanged || centerChanged) {

                mapEvent = new MapEvent(MapEvent.MOVE_START, this);
                mapEvent.oldZoom = oldZoom;
                mapEvent.newZoom = newZoom;
                mapEvent.oldCenter = oldCenter;
                mapEvent.newCenter = newCenter;
                this.dispatchEvent(mapEvent);

                if (zoomChanged && zoomTween) {
                    this.zoomTransition(newZoom, newCenter);
                    return;
                }

                if (centerChanged) {
                    if ((!zoomChanged) && (this.center)) {
                        this.centerLayerContainer(newCenter, dragTween);
                    }
                    this._center = newCenter.clone();
                }

                if ((zoomChanged) || (this._layerContainerOrigin == null)) {
                    this._layerContainerOrigin = this.center.clone();
                    this._layerContainer.x = 0;
                    this._layerContainer.y = 0;
                }

                if (zoomChanged) {
                    this._zoom = newZoom;
                }

                if (!dragTween) {
                    mapEvent = new MapEvent(MapEvent.MOVE_END, this);
                    mapEvent.oldZoom = oldZoom;
                    mapEvent.newZoom = newZoom;
                    mapEvent.oldCenter = oldCenter;
                    mapEvent.newCenter = newCenter;
                    this.dispatchEvent(mapEvent);

                }
            }
        }

        /**
         * This function takes care to recenter the layerContainer and bitmapTransition.
         *
         * @param lonlat the new layer container center
         * @param tween use tween effect if set to true
         */
        private function centerLayerContainer(lonlat:Location, tween:Boolean = false):void {

            var originPx:Pixel = this.getMapPxFromLocation(this._layerContainerOrigin);
            var newPx:Pixel = this.getMapPxFromLocation(lonlat);

            if (originPx == null || newPx == null)
                return;

            // X and Y positions for the layer container and bitmap transition, respectively.
            var lx:Number = originPx.x - newPx.x;
            var ly:Number = originPx.y - newPx.y;
            if (bitmapTransition != null) {
                var bx:Number = bitmapTransition.x + lx - _layerContainer.x;
                var by:Number = bitmapTransition.y + ly - _layerContainer.y;
            }

            if (tween) {
                var layerContainerTween:GTween = new GTween(this._layerContainer, 0.5, {x: lx, y: ly}, {ease: Cubic.easeOut});
                layerContainerTween.onComplete = onDragTweenComplete;
                if (bitmapTransition != null) {
                    new GTween(bitmapTransition, 0.5, {x: bx, y: by}, {ease: Cubic.easeOut});
                }
            }
            else {
                this._layerContainer.x = lx;
                this._layerContainer.y = ly;
                if (bitmapTransition != null) {
                    bitmapTransition.x = bx;
                    bitmapTransition.y = by;
                }
            }
        }

        private function onDragTweenComplete(tween:GTween):void {
            this.dispatchEvent(new MapEvent(MapEvent.MOVE_END, this));
        }

        /**
         * 是否valid的zoomlevel
         */
        public function isValidZoomLevel(zoomLevel:Number):Boolean {
            return (!isNaN(zoomLevel) && (zoomLevel >= 0) && (zoomLevel <= this.resolutions.length - 1));
        }

        /**
         *  是否valid的location
         */
        public function isValidLocation(lonlat:Location):Boolean {
            return (lonlat != null); //&& this.maxExtent.containsLocation(lonlat);
        }

        /**
         * 放大到指定的地图范围
         *
         * @param 地图范围
         */
        public function zoomToExtent(bounds:Extent):void {
            this.moveTo(bounds.center, this.getZoomForExtent(bounds));
        }

        /**
         * 放大到最大范围
         */
        public function zoomToMaxExtent():void {
            this.zoomToExtent(this.maxExtent);
        }

        /**
         * 地图像素坐标--location转换
         */
        public function getLocationFromMapPx(viewPortPx:Pixel):Location {
            var lonlat:Location = null;
            if (viewPortPx != null) {
                var size:Size = this.size;
                var center:Location = this.center;
                if (center) {
                    var res:Number = this.resolution;

                    var delta_x:Number = viewPortPx.x - (size.w / 2);
                    var delta_y:Number = viewPortPx.y - (size.h / 2);

                    lonlat = new Location(center.lon + delta_x * res, center.lat - delta_y * res, this._projection);
                }
            }
            return lonlat;
        }

        /**
         * 地图location--像素坐标转换
         */
        public function getMapPxFromLocation(lonlat:Location):Pixel {
            var px:Pixel = null;
            if (lonlat != null) {
                var resolution:Number = this.resolution;
                var extent:Extent = this.extent;
                px = new Pixel(Math.round((lonlat.lon - extent.xmin) / resolution), Math.round((extent.ymax - lonlat.lat) / resolution));
            }
            return px;
        }

        /**
         * 图层像素坐标---地图像素坐标转换，考虑到layercontainer的偏移量
         */
        public function getMapPxFromLayerPx(layerPx:Pixel):Pixel {
            var viewPortPx:Pixel = null;
            if (layerPx != null) {
                var dX:int = int(this._layerContainer.x);
                var dY:int = int(this._layerContainer.y);
                viewPortPx = layerPx.add(dX, dY);
            }
            return viewPortPx;
        }

        /**
         * 地图像素坐标---图层像素坐标转换，考虑到layercontainer的偏移量
         */
        public function getLayerPxFromMapPx(mapPx:Pixel):Pixel {
            var layerPx:Pixel = null;
            if (mapPx != null) {
                var dX:int = -int(this._layerContainer.x);
                var dY:int = -int(this._layerContainer.y);
                layerPx = mapPx.add(dX, dY);
            }
            return layerPx;
        }

        /**
         * 地图location--图层像素坐标转换
         */
        public function getLocationFromLayerPx(px:Pixel):Location {
            px = this.getMapPxFromLayerPx(px);
            return this.getLocationFromMapPx(px);
        }

        /**
         * 地图location--图层像素坐标转换
         */
        public function getLayerPxFromLocation(lonlat:Location):Pixel {
            var px:Pixel = this.getMapPxFromLocation(lonlat);
            return this.getLayerPxFromMapPx(px);
        }

        /**
         * 地图中心点坐标
         */
        public function get center():Location {
            if (_center == null) {
                _center = new Location((maxExtent.xmax + maxExtent.xmin) / 2, (maxExtent.ymax + maxExtent.ymin) / 2);
            }
            return _center;
        }

        public function set center(newCenter:Location):void {
            this.moveTo(newCenter);
            this._center = newCenter;
        }

        /**
         * 当前zoom level
         */
        public function get zoom():Number {
            return _zoom;
        }

        public function set zoom(newZoom:Number):void {
            this.moveTo(this.center, newZoom);
            this._zoom = newZoom;
        }

        /**
         * Copy the layerContainer in a bitmap and display this (this function is use for zoom)
         */
        private function zoomTransition(newZoom:Number, newCenter:Location):void {
            if (!_zooming && newZoom >= 0) {
                // Disable more zooming until this zooming is complete
                this._zooming = true;

                // We calculate de scale multiplicator according to the actual and new resolution
                var resMult:Number = this.resolution / this.resolutions[newZoom];
                // We intsanciate a bitmapdata with map's size
                var bitmapData:BitmapData = new BitmapData(this.width, this.height);

                // We draw the old transition before drawing the better-fitting tiles on top and removing the old transition.
                if (this.bitmapTransition != null) {
                    if (this._loading) {
                        bitmapData.draw(this.bitmapTransition, bitmapTransition.transform.matrix);
                    }
                    this.removeChild(this.bitmapTransition);
                    var bmp:Bitmap = bitmapTransition.removeChildAt(0) as Bitmap;
                    bmp.bitmapData.dispose();
                    bmp.bitmapData = null;
                }

                var hiddenLayers:Vector.<Layer> = new Vector.<Layer>();
                for each (var layer:Layer in this.layers) {
                    if (!layer.tweenOnZoom && layer.visible) {
                        hiddenLayers.push(layer);
                        layer.visible = false;
                    }
                }

                // We draw the loaded tiles onto the background transition.
                try {
                    // Can sometimes throw a security exception.
                    bitmapData.draw(this.layerContainer, this.layerContainer.transform.matrix);
                }
                catch (e:Error) {
                    trace("Error zooming image: " + e);
                }

                // We create the background layer from the bitmap data
                this.bitmapTransition = new Sprite();
                var bitmap:Bitmap = new Bitmap(bitmapData);
                bitmap.smoothing = true;
                this.bitmapTransition.addChild(bitmap);
                this.addChildAt(bitmapTransition, 0);

                // We hide the layerContainer (to avoid zooming out issues)
                this.layerContainer.visible = false;
                for each (var hiddenLayer:Layer in hiddenLayers) {
                    hiddenLayer.visible = true;
                }

                //We calculate the bitmapTransition position
                var pix:Pixel = this.getMapPxFromLocation(newCenter);
                var bt:Sprite = this.bitmapTransition;
                var oldCenterPix:Pixel = new Pixel(bt.x + bt.width / 2, bt.y + bt.height / 2);
                var centerOffset:Pixel = new Pixel(oldCenterPix.x - pix.x, oldCenterPix.y - pix.y);
                var alpha:Number = Math.pow(2, newZoom - this.zoom);
                var x:Number = bt.x - ((resMult - 1) * (bt.width)) / 2 + alpha * centerOffset.x;
                var y:Number = bt.y - ((resMult - 1) * (bt.height)) / 2 + alpha * centerOffset.y;

                //The tween effect to scale and re-position the bitmapTransition
                var tween:GTween = new GTween(this.bitmapTransition, 0.3, {scaleX: resMult, scaleY: resMult, x: x, y: y}, {ease: Cubic.easeOut});
                tween.onComplete = clbZoomTween;
            }

            // The zoom tween callback method defined here to avoid a class attribute for newZoom
            function clbZoomTween(tween:GTween):void {
                _zooming = false;
                moveTo(newCenter, newZoom);
                layerContainer.visible = true;
                clearBitmapTransition();
            }

        }

        public function clearBitmapTransition():void {
            if (this._bitmapTransition != null && this._bitmapTransition.visible && this.tileLayerLoadComplete()) {
                this._bitmapTransition.visible = false;
            }
        }

        /**
         * 是否瓦片图层加载完
         */
        private function tileLayerLoadComplete():Boolean {
            // check all layers
            var l:Vector.<Layer> = this.layers;
            var i:int = l.length - 1;
            for (i; i > -1; i--) {
                var layer:Layer = l[i];
                if (layer != null) {
                    if (!(layer is FeatureLayer)) {
                        if (!layer.loadComplete) {
                            return false;
                        }
                    }
                }
            }
            return true;
        }

        /**
         * Event handler for LayerLoadComplete event. Check here if all layers have been loaded
         * and if so, MapEvent.LOAD_COMPLETE can be dispatched
         */
        private function layerLoadHandler(event:LayerEvent):void {

            switch (event.type) {
                case LayerEvent.LAYER_LOAD_START:  {
                    if (event.layer is FeatureLayer) {
                        //只对featurelayer的load状态在界面上显示等待漏斗符号
                        this.loading = true;
                    }
                    break;
                }
                case LayerEvent.LAYER_LOAD_END:  {
                    layerContainer.visible = true;
                    clearBitmapTransition();

                    // check all feature layers
                    var layers:Vector.<FeatureLayer> = this.featureLayers;
                    var i:int = this.featureLayers.length - 1;
                    for (i; i > -1; i--) {
                        var layer:FeatureLayer = layers[i];
                        if (layer != null && !layer.loadComplete)
                            return;
                    }

                    // all layers are loaded.
                    this.loading = false;

                    break;
                }
            }
        }

        /**
         * 地图大小（宽、高 像素）
         */
        public function get size():Size {
            return (_size) ? _size.clone() : null;
        }

        public function set size(value:Size):void {
            _size = value;
            if (value && this._resolutions) {
                this.graphics.clear();
                this.graphics.beginFill(0xFFFFFF, 0);
                this.graphics.drawRect(0, 0, this.size.w, this.size.h);
                this.graphics.endFill();

                //设置scrollrect
                this.scrollRect = new Rectangle(0, 0, this.size.w, this.size.h);

                this.layerContainer.graphics.clear();
                this.layerContainer.graphics.beginFill(0xFFFFFF, 0);
                this.layerContainer.graphics.drawRect(0, 0, this.size.w, this.size.h);
                this.layerContainer.graphics.endFill();

                this.dispatchEvent(new MapEvent(MapEvent.RESIZE, this));

                this.moveTo(null, this.zoom);

                this._mapSupport.refreshDefaultControls();
            }
        }

        /**
         * 地图宽
         */
        override public function set width(value:Number):void {
            if (!isNaN(value)) {
                this.size = new Size(value, this.height);
            }
        }

        /**
         * 地图高
         */
        override public function set height(value:Number):void {
            if (!isNaN(value)) {
                this.size = new Size(this.width, value);
            }
        }

        /**
         * 地图控件
         */
        public function get controls():Vector.<IControl> {
            return this._controls;
        }

        /**
         * 地图操作handlers
         */
        public function get handlers():Vector.<IHandler> {
            return this._handlers;
        }

        /**
         * 图层的容器对象，用户地图移动及放大缩小.
         */
        public function get layerContainer():Sprite {
            return this._layerContainer;
        }

        /**
         * tween效果的bitmapTransition
         */
        public function get bitmapTransition():Sprite {
            return this._bitmapTransition;
        }

        public function set bitmapTransition(value:Sprite):void {
            this._bitmapTransition = value;
        }

        public function set maxExtent(value:Extent):void {
            this._maxExtent = value;
        }

        /**
         * 地图的最大范围
         */
        public function get maxExtent():Extent {
            var maxExtent:Extent = this._maxExtent;
            if (maxExtent == null) {
                maxExtent = Map.DEFAULT_MAXEXTENT;
                if ((this.projection.srsCode != Map.DEFAULT_SRS_CODE)) {
                    maxExtent.transform(Map.DEFAULT_PROJECTION, this.projection)
                }
            }
            return maxExtent;
        }

        /**
         * 当前的地图Extent
         */
        public function get extent():Extent {
            var extent:Extent = null;

            if ((this.center != null) && (this.resolution != -1)) {

                var w_deg:Number = this.size.w * this.resolution;
                var h_deg:Number = this.size.h * this.resolution;

                extent = new Extent(this.center.lon - w_deg / 2, this.center.lat - h_deg / 2, this.center.lon + w_deg / 2, this.center.lat + h_deg / 2, this.projection);
            }

            return extent;

        }

        /**
         * 当前地图分辨率
         */
        public function get resolution():Number {
            return this.resolutions[this.zoom];
        }

        /**
         * 当前比例尺
         */
        public function get scale():Number {
            var scale:Number = NaN;
            var units:String = this.projection.projParams.units;
            scale = Unit.getScaleFromResolution(this.resolution, units);
            return scale;
        }

        /**
         * 获取地图的所有图层
         */
        public function get layers():Vector.<Layer> {
            var layerArray:Vector.<Layer> = new Vector.<Layer>();
            if (this.layerContainer == null) {
                return layerArray;
            }
            var s:DisplayObject;
            var i:int = this.layerContainer.numChildren - 1;
            for (i; i > -1; --i) {
                s = this.layerContainer.getChildAt(i);
                if (s is Layer) {
                    layerArray.push(s);
                }
            }
            return layerArray.reverse();
        }

        /**
         * 获取某个图层的显示index
         * @param 要修改的图层
         * @return  index值
         * */
        public function getLayerIndex(layer:Layer):int {
            return this.layerContainer.getChildIndex(layer);
        }

        /**
         * 修改图层显示顺序到一定的值
         * @param 要修改的图层
         * @param 新的index值 (index小的在上面)
         * */
        public function changeLayerIndex(layer:Layer, newIndex:int):void {
            var length:int = this.layerContainer.numChildren;
            var newIndexTemp:int = length - newIndex - 1;
            if (newIndex >= 0 && newIndex < length)
                this.layerContainer.setChildIndex(layer, newIndexTemp); // the tab of layer are inverse
            this.dispatchEvent(new LayerEvent(LayerEvent.LAYER_CHANGED_ORDER, layer));
        }

        /**
         * 上下移动图层的显示顺序
         * @param 要修改的图层
         * @param 图层显示顺序的偏移量（正、负值）
         * */
        public function changeLayerIndexByStep(layer:Layer, step:int):void {
            var indexLayer:int = this.layerContainer.getChildIndex(layer);
            var length:int = this.layerContainer.numChildren;
            var newIndex:int = indexLayer + step;
            if (newIndex >= 0 && newIndex < length)
                this.layerContainer.setChildIndex(layer, newIndex);
            //- cause the ordre is not the same that the dysplay order
            this.dispatchEvent(new LayerEvent(LayerEvent.LAYER_CHANGED_ORDER, layer));
        }

        /**
         * 得到所有的featurelayers
         **/
        public function get featureLayers():Vector.<FeatureLayer> {
            var layerArray:Vector.<FeatureLayer> = new Vector.<FeatureLayer>();
            if (this.layerContainer == null) {
                return layerArray;
            }
            var s:DisplayObject;
            var i:int = this.layerContainer.numChildren - 1;
            for (i; i > -1; i--) {
                s = this.layerContainer.getChildAt(i);
                if (s is FeatureLayer) {
                    layerArray.push(s);
                }
            }
            return layerArray.reverse();
        }

        /**
         * 跨域访问代理
         * 也可用 crossdomain.xml文件实现
         */
        public function get proxy():String {
            return this._proxy
        }

        public function set proxy(value:String):void {
            this._proxy = value;
        }

        /**
         * 地图放大缩小tween效果
         */
        public function set tweenZoomEnabled(value:Boolean):void {
            _tweenZoomEnabled = value;
        }

        public function get tweenZoomEnabled():Boolean {
            return _tweenZoomEnabled;
        }

        /**
         * 地图是否加载完毕
         */
        public function get loadComplete():Boolean {
            return !this._loading;
        }

        /**
         * 地图加载状态，
         * 触发loadstart和loadend事件
         */
        public function set loading(value:Boolean):void {
            if (value == true && this._loading == false) {
                this._loading = value;
                dispatchEvent(new MapEvent(MapEvent.LOAD_START, this));
            }

            if (value == false && this._loading == true) {
                this._loading = value;
                dispatchEvent(new MapEvent(MapEvent.LOAD_END, this));
            }
        }

        /**当前投影*/
        public function get projection():Projection {
            return this._projection;
        }

        public function set projection(value:Projection):void {
            this._projection = value;
        }

        /**地图的高，根据size获取*/
        override public function get height():Number {
            return this._size.h;
        }

        /**地图的宽，根据size获取*/
        override public function get width():Number {
            return this._size.w;
        }

        /**矢量符号库*/
        public function get symbolDic():Dictionary {
            return _symbolDic;
        }

        public function set symbolDic(value:Dictionary):void {
            _symbolDic = value;
        }

        /**获取选择设施集
         * 根据每个图层的selectedFeatures生成
         */
        public function get selectedFeatures():Vector.<Feature> {
            var _selectedFeatures:Vector.<Feature> = new Vector.<Feature>();

            //遍历featurelayer获取已选择的设施
            var feaLayers:Vector.<FeatureLayer> = this.featureLayers;
            for each (var feaLayer:FeatureLayer in feaLayers) {
                for each (var fea:Feature in feaLayer.selectedFeatures) {
                    _selectedFeatures.push(fea);
                }
            }
            return _selectedFeatures;
        }

		
		
        public function get legendControl():ILegendDisplayControlAware {
//            if (_legendControl == null) {
//                _legendControl = new LegendDisplayControl()
//            }
            return _legendControl;
        }

        public function set legendControl(value:ILegendDisplayControlAware):void {
            _legendControl = value;
        }

        /**远程数据服务*/
        public function get remoteCaller():RemoteCaller {
            return _remoteCaller;
        }

        /**
         * @private
         */
        public function set remoteCaller(value:RemoteCaller):void {
            _remoteCaller = value;
        }

        /**
         * 清空选择集
         */
        public function clearSelection():void {
            for each (var layer:FeatureLayer in this.featureLayers) {
                for each (var feaTmp:Feature in layer.selectedFeatures) {
                    feaTmp.selected = false;
                    feaTmp.executeDrawing();
                }
            }
        }

		/**
		 * 清空高亮集
		 */
		public function clearHighLight():void {
			if(this.highLightFeatures.length==0){
				return;
			}
			for each (var feaTmp:Feature in this.highLightFeatures) {
					feaTmp.highLighted = false;
					feaTmp.executeDrawing();
				
			}
		}
		
        /**
         * 定位指定图层中的指定objectid的图形
         * @param layerid 图层id
         * @param objectid 对象的id
         * @param highlightmode  结果集的显示方式
         * @param centered 是否居中显示
         * @param appendmode 是否追加模式，true:不清除掉原来的高亮设施
         */
        public function QueryAndLocateFeatureById(layerid:Number, objectid:Number, zoomlevel:Number = 14, centered:Boolean = true, appendmode:Boolean = false, spec:Object = null):void {
            this._mapSupport.QueryAndLocateFeatureById(layerid, objectid, zoomlevel, centered, appendmode, spec);
        }

        /**
         * 定位指定图层中的objectids数组
         * @param layerid 图层id
         * @param objectidList 对象的id数组
         * @param appendmode 是否追加模式，true:不清除掉原来的高亮设施
         */
        public function QueryAndLocateFeaturesByIds(layerid:Number, objectidList:ArrayCollection, centered:Boolean = true, appendmode:Boolean = false, hilighted:Boolean = true):void {
            this._mapSupport.QueryAndLocateFeaturesByIds(layerid, objectidList, centered, appendmode, hilighted);
        }

        public function get logicalMapId():Number {
            return _logicalMapId;
        }

        public function set logicalMapId(value:Number):void {
            _logicalMapId = value;
        }

        /**
         *
         *刷新所有的图层
         * */
        public function refreshAllFeatureLayer():void {
            var layers:Vector.<FeatureLayer> = this.featureLayers;
            for (var i:int = 0; i < layers.length; i++) {
                layers[i].redraw(true);
            }
        }

        /**
         * 将所有图层设置选择状态
         * */
        public function setAllFeatureLayerSelectEnabled(value:Boolean):void {
            var layers:Vector.<FeatureLayer> = this.featureLayers;
            for (var i:int = 0; i < layers.length; i++) {
                layers[i].selectable = value;
            }
        }

        public function inVisiableAllControls():void {
            for each (var control:IControl in this.controls) {
                control.visiable = false;
            }
        }


		public function get highLightFeatures():Vector.<Feature>
		{
			return this._highLightFeatures;
		}
		
		public function set highLightFeatures(value:Vector.<Feature>):void
		{
			this._highLightFeatures=value;
		}
    }
}